package com.sitech.openapi.componet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ObjectTree {


    private final Log logger = LogFactory.getLog(ObjectTree.class);

    protected TreeNode node;

    protected final static int mb_set_all = 0;

    protected final static int mb_set_value = 1;

    protected final static int mb_set_attr = 2;

    /**
     * 创建一个新的实例 ObjectTree.
     */
    public ObjectTree() {
        this.node = new TreeNode();
    }

    /**
     * 创建一个新的实例 ObjectTree.
     *
     * @param rkey
     *            节点名称
     * @param cnode
     *            节点值
     */
    public ObjectTree(String rkey, TreeNode cnode) {
        this.node = new TreeNode();
        Map map = this.node.getIterator();
        map.put(rkey, cnode);
    }

    /**
     * 设置值和属性
     *
     * @param key
     *            抽象路径
     * @param value
     *            节点值
     * @param attrStrs
     *            节点属性
     */
    protected void setValueAndAttr(int mode, String key, Object value, String... attrStrs) {

        if (value == null) {
            value = "";
        }

        String[] keys = key.split("\\.");
        int len = keys.length;

        Map p_map = this.node.getIterator();

        TreeNode cnode = null;
        StringBuffer nodePathBuffer = new StringBuffer(key.length());
        for (int i = 0; i < len - 1; i++) {
            nodePathBuffer.append(keys[i]+".");
            String nodePath = nodePathBuffer.toString().substring(0, nodePathBuffer.length()-1);
            int pos = keys[i].indexOf("[");
            if (pos != -1) {
                String rkey = keys[i].substring(0, pos);
                int rpos = Integer.parseInt(keys[i].substring(pos + 1,
                        keys[i].length() - 1));
                Object lvalue = p_map.get(rkey);
                if (lvalue == null) {
                    lvalue = new ArrayList<TreeNode>();
                    p_map.put(rkey, lvalue);
                }

                if (rpos + 1 > ((List) lvalue).size()) {
                    cnode = new TreeNode();
                    cnode.setNodePath(nodePath);
                    p_map = cnode.getIterator();
                    ((List) lvalue).add(cnode);
                } else {
                    if (((List) lvalue).get(rpos) == null) {
                        cnode = new TreeNode();
                        cnode.setNodePath(nodePath);
                        p_map = cnode.getIterator();
                        ((List) lvalue).add(rpos, cnode);
                    } else {
                        p_map = ((TreeNode) ((List) lvalue).get(rpos)).getIterator();
                        logger.trace("Node 已经存在, 直接返回!");
                    }
                }

            } else {
                if (p_map.get(keys[i]) == null) {
                    cnode = new TreeNode();
                    cnode.setNodePath(nodePath);
                    p_map.put(keys[i], cnode);
                }
                p_map = ((TreeNode) p_map.get(keys[i])).getIterator();
            }
        }

        // 解析属性 attr1:123,attr2:456
        LinkedHashMap<String, String> attrMap = this.attrToMap(attrStrs);

        int pos = keys[(len - 1)].indexOf("[");
        if (pos != -1) {
            String rkey = keys[(len - 1)].substring(0, pos);
            int rpos = Integer.parseInt(keys[(len - 1)].substring(pos + 1,
                    keys[(len - 1)].length() - 1));
            Object lvalue = p_map.get(rkey);
            if (lvalue == null) {
                lvalue = new ArrayList<TreeNode>();
                p_map.put(rkey, lvalue);
            }

            if (rpos + 1 > ((List) lvalue).size()) {
                TreeNode leaf_node = new TreeNode();
                this.setValueOrAttrByMode(mode, leaf_node, value, attrMap);
                leaf_node.setNodePath(key);
                ((List) lvalue).add(leaf_node);
            } else {
                TreeNode nodeList = (TreeNode) ((List) lvalue).get(rpos);
                if (nodeList == null) {
                    TreeNode leaf_node = new TreeNode();
                    this.setValueOrAttrByMode(mode, leaf_node, value, attrMap);
                    leaf_node.setNodePath(key);
                    ((List) lvalue).add(rpos, leaf_node);
                } else {
                    nodeList.setNodePath(key);
                    this.setValueOrAttrByMode(mode, nodeList, value, attrMap);
                }
            }

        } else {
            if (p_map.get(keys[(len - 1)]) == null) {
                TreeNode leaf_node = new TreeNode();
                this.setValueOrAttrByMode(mode, leaf_node, value, attrMap);
                leaf_node.setNodePath(key);
                p_map.put(keys[(len - 1)], leaf_node);
            } else {
                TreeNode leaf_node = (TreeNode) p_map.get(keys[(len - 1)]);
                leaf_node.setNodePath(key);
                this.setValueOrAttrByMode(mode, leaf_node, value, attrMap);
            }
        }

    }

    private TreeNode setValueOrAttrByMode(int mode, TreeNode leaf_node,
                                          Object value, LinkedHashMap<String, String> attrMap) {

        if (mb_set_all == mode) { // 设置属性 和值
            leaf_node.setNodeValue(value);
            leaf_node.setNodeAttr(attrMap);
        }

        if (mb_set_value == mode) { // 只设置值
            leaf_node.setNodeValue(value);
        }

        if (mb_set_attr == mode) { // 只设置属性
            leaf_node.setNodeAttr(attrMap);
        }

        return leaf_node;
    }

    /**
     * 根据抽象路径获取TreeNode节点
     *
     * @param key
     *            抽象路径
     * @return TreeNode 返参
     */
    protected TreeNode getNode(String key) {

        String[] keys = key.split("\\.");
        int len = keys.length;
        Map p_map = this.node.getIterator();
        for (int i = 0; i < len - 1; ++i) {
            int pos = keys[i].indexOf("[");
            if (pos != -1) {
                String rkey = keys[i].substring(0, pos);
                if (!(p_map.containsKey(rkey))) {
                    return null;
                }
                int rpos = Integer.parseInt(keys[i].substring(pos + 1,
                        keys[i].length() - 1));
                Object obj = p_map.get(rkey);
                if (obj instanceof List) {
                    if (rpos >= ((List) p_map.get(rkey)).size()) {
                        return null;
                    }
                    p_map = ((TreeNode) ((List) p_map.get(rkey)).get(rpos))
                            .getIterator();
                } else {
                    p_map = ((TreeNode) p_map.get(rkey)).getIterator();
                }

            } else {
                if (!(p_map.containsKey(keys[i]))) {
                    return null;
                }
                if (!(p_map.get(keys[i]) instanceof TreeNode)) {
                    return null;
                }
                p_map = ((TreeNode) p_map.get(keys[i])).getIterator();
            }
        }

        Object value = null;
        TreeNode ret_node = null;
        int pos = keys[(len - 1)].indexOf("[");
        if (pos != -1) {
            String rkey = keys[(len - 1)].substring(0, pos);
            if (!(p_map.containsKey(rkey))) {
                return null;
            }
            int rpos = Integer.parseInt(keys[(len - 1)].substring(pos + 1,
                    keys[(len - 1)].length() - 1));
            value = p_map.get(rkey);
            if (value instanceof List) {
                ret_node = (TreeNode) ((List) value).get(rpos);
            } else {
                ret_node = (TreeNode) value;
            }

        } else {
            if (!(p_map.containsKey(keys[(len - 1)]))) {
                return null;
            }
            ret_node = (TreeNode) p_map.get(keys[(len - 1)]);
        }

        return ret_node;
    }



    /**
     *  根据抽象路径key 获取  符合这个路径的  所有的 节点
     *  <p>
     *  <root>
     *		<a>
     *			<b>
     *				<c>111</c>
     *			</b>
     *		</a>
     *		<a>
     *			<b>
     *				<c>222</c>
     *			</b>
     *		</a>
     *	</root>
     *
     *  root.a.b.c /  root.a.b[1].c[1] / root.a.b.c[1]
     *
     *  <p>
     * @param key
     * @return
     */
    protected List<TreeNode> getNodeAll(String key) {

        String[] keys = key.split("\\.");
        int len = keys.length;
        Map p_map_root = this.node.getIterator();
        List<Map> p_map_list = new ArrayList();
        p_map_list.add(p_map_root);
        for (int i = 0; i < len - 1; ++i) { // 首先找到除 最后一个节点路径的 所有 指针 ; 比如
            // a.b.c.d 则找到 a.b.c 的所有map指针 。
            int pos = keys[i].indexOf("[");
            List<Map> list = new ArrayList();
            if (pos != -1) {
                String rkey = keys[i].substring(0, pos);
                int rpos = Integer.parseInt(keys[i].substring(pos + 1,
                        keys[i].length() - 1));

                for (Map p_map_c : p_map_list) {
                    if (!(p_map_c.containsKey(rkey))) {
                        continue;
                    }
                    Object obj = p_map_c.get(rkey);
                    if (obj instanceof List) {
                        if (rpos >= ((List) p_map_c.get(rkey)).size()) {
                            throw new RuntimeException( "节点名称为 ： " + rkey
                                    + ", 节点索引 ：" + rpos + "不存在");
                        }
                        list.add(((TreeNode) ((List) p_map_c.get(rkey)).get(rpos)).getIterator());
                    } else {
                        list.add(((TreeNode) p_map_c.get(rkey)).getIterator());
                    }

                }
                p_map_list = list;

            } else {
                for (Map p_map_c : p_map_list) {
                    if (!(p_map_c.containsKey(keys[i]))) {
                        continue;
                    }
                    Object obj = p_map_c.get(keys[i]);
                    if (obj instanceof List) {
                        for (TreeNode node : (List<TreeNode>) obj) {
                            list.add(node.getIterator());
                        }
                    } else {
                        list.add(((TreeNode) obj).getIterator());
                    }
                }
                p_map_list = list;
            }
        }

        // 根据最后一个节点 组织输出的值 ; 例如 a.b.c.d 则找到 a.b.c 的所有map指针 。 然后从map 指针找到 d 的值
        List<TreeNode> ret_list = new ArrayList<TreeNode>();
        Object value = null;
        TreeNode ret_node = null;
        int pos = keys[(len - 1)].indexOf("[");
        if (pos != -1) {
            String rkey = keys[(len - 1)].substring(0, pos);
            int rpos = Integer.parseInt(keys[(len - 1)].substring(pos + 1,
                    keys[(len - 1)].length() - 1));

            for (Map p_map_c : p_map_list) {
                if (!(p_map_c.containsKey(rkey))) {
                    continue;
                }
                value = p_map_c.get(rkey);
                if (value instanceof List) {
                    if (rpos >= ((List) p_map_c.get(rkey)).size()) {
                        throw new RuntimeException("节点名称为 ： " + rkey + ", 节点索引 ：" + rpos + "不存在");
                    }
                    ret_node = (TreeNode) ((List) value).get(rpos);
                } else {
                    ret_node = (TreeNode) value;
                }
                ret_list.add(ret_node);
            }

        } else {
            for (Map p_map_c : p_map_list) {
                if (!(p_map_c.containsKey(keys[(len - 1)]))) {
                    continue;
                }
                Object obj = p_map_c.get(keys[(len - 1)]);
                if (obj instanceof List) {
                    for (TreeNode node : (List<TreeNode>) obj) {
                        ret_list.add(node);
                    }
                } else {
                    ret_node = (TreeNode) p_map_c.get(keys[(len - 1)]);
                    ret_list.add(ret_node);
                }
            }
        }

        return ret_list;
    }


    /**
     * 获取路径节点个数
     *
     * @param key
     *            抽象路径
     * @return int 节点个数
     */
    protected int getListNum(String key) {
        String[] keys = key.split("\\.");
        int len = keys.length;
        Map p_map = this.node.getIterator();
        for (int i = 0; i < len - 1; ++i) {
            int pos = keys[i].indexOf("[");
            if (pos != -1) {
                String rkey = keys[i].substring(0, pos);
                if (!(p_map.containsKey(rkey))) {
                    return 0;
                }
                int rpos = Integer.parseInt(keys[i].substring(pos + 1,
                        keys[i].length() - 1));
                Object obj = p_map.get(rkey);
                if (obj instanceof List) {
                    if (rpos >= ((List) p_map.get(rkey)).size()) {
                        return 0;
                    }
                    p_map = ((TreeNode) ((List) p_map.get(rkey)).get(rpos))
                            .getIterator();
                } else {
                    p_map = ((TreeNode) p_map.get(rkey)).getIterator();
                }

            } else {
                if (!(p_map.containsKey(keys[i]))) {
                    return 0;
                }
                if (!(p_map.get(keys[i]) instanceof TreeNode)) {
                    return 0;
                }
                p_map = ((TreeNode) p_map.get(keys[i])).getIterator();
            }
        }

        Object value = null;
        int list_num = 0;
        int pos = keys[(len - 1)].indexOf("[");
        if (pos != -1) {
            return 0;
        } else {
            if (!(p_map.containsKey(keys[(len - 1)]))) {
                return 0;
            }
            value = p_map.get(keys[(len - 1)]);
            if (value instanceof List) {
                list_num = ((List) value).size();
            } else {
                list_num = 1;
            }
        }

        return list_num;
    }

    /**
     * 移除MapBean的一个节点
     *
     * @param key
     *            需要移除的节点
     */
    protected void removeNode(String key) {

        int lastMark = key.lastIndexOf(".");
        String parentKey = key.substring(0, lastMark);
        String childKey = key.substring(lastMark + 1);

        TreeNode cnode = this.getNode(parentKey);
        if (cnode == null) {
            return;
        }

        int pos = childKey.indexOf("[");
        if (pos != -1) {
            String rkey = childKey.substring(0, pos);
            int rpos = Integer.parseInt(childKey.substring(pos + 1,
                    childKey.length() - 1));
            Object childNodeList = cnode.getIterator().get(rkey);
            if (childNodeList instanceof List) {
                ((List) childNodeList).remove(rpos);
            }

        } else {
            cnode.getIterator().remove(childKey);
        }
    }

    /**
     * 属性数值转Map
     *
     * @param attrStrs
     *            属性数值
     * @return LinkedHashMap 属性Map
     */
    private LinkedHashMap<String, String> attrToMap(String... attrStrs) {

        LinkedHashMap<String, String> attrMap = null;

        if (attrStrs.length == 0) {

        } else {
            attrMap = new LinkedHashMap<String, String>();
            for (int i = 0; i < attrStrs.length; i++) {
                String[] attrs = attrStrs[i].split("\\:");
                if (attrs.length != 2) {
                    break;
                }
                attrMap.put(attrs[0], attrs[1]);
            }
        }
        return attrMap;
    }

    public class TreeNode {

        public LinkedHashMap<String, Object> Iterator;

        public LinkedHashMap<String, String> NodeAttr;

        public Object nodeValue;

        public String nodePath;

        public TreeNode() {
            this.Iterator = new LinkedHashMap<String, Object>();
        }


        public LinkedHashMap<String, Object> getIterator() {
            return Iterator;
        }

        public void setIterator(LinkedHashMap<String, Object> iterator) {
            Iterator = iterator;
        }

        public LinkedHashMap<String, String> getNodeAttr() {
            return NodeAttr;
        }

        public void setNodeAttr(LinkedHashMap<String, String> nodeAttr) {
            NodeAttr = nodeAttr;
        }

        public Object getNodeValue() {
            return nodeValue;
        }

        public void setNodeValue(Object nodeValue) {
            this.nodeValue = nodeValue;
        }

        public String getNodePath() {
            return nodePath;
        }

        public void setNodePath(String nodePath) {
            this.nodePath = nodePath;
        }

    }

}
